<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:f="livcos.org/ns/xslt/function"
  xmlns:t="livcos.org/ns/cosmos/type"
  exclude-result-prefixes="t f">
  
  <xsl:template name="idPath">
    <xsl:param name="id"/>
  	<xsl:text>.</xsl:text>
  	<xsl:for-each select="tokenize($id, '\.')">
  		<xsl:text>/</xsl:text>
  		<xsl:choose>
  			<xsl:when test=". = ''">
  				<xsl:text>.</xsl:text>
  			</xsl:when>
  			<xsl:when test="(. = '1') and (position() = 1)">
  				<!-- a starting '1' represents the context element (normally the root element) -->
  				<xsl:text>.</xsl:text>
  			</xsl:when>
  			<xsl:when test="starts-with(.,'@xmlns')">
  				<!-- ignore for now and address the owner element...
  					<xsl:text>/namespace::*[local-name(.) = '</xsl:text>
  					<xsl:value-of select="substring($tk, 8)" />
  					<xsl:text>']</xsl:text-->
  			</xsl:when>
  			<xsl:when test="starts-with(.,'@')">
  				<xsl:value-of select="." />
  			</xsl:when>
  			<xsl:when test="matches(.,'^[0-9]+$')">
  				<xsl:text>node()[</xsl:text>
  				<xsl:value-of select="."/>
  				<xsl:text>]</xsl:text>
  			</xsl:when>
  			<xsl:otherwise>
  				<xsl:text>/*[@id = '</xsl:text>
  				<xsl:value-of select="." />
  				<xsl:text>']</xsl:text>
  			</xsl:otherwise>
  		</xsl:choose>
  	</xsl:for-each>
  </xsl:template>
  
	<xsl:template name="applyNode">
    <xsl:param name="parentNode"/>
    <xsl:param name="id"/>
		<xsl:variable name="tk" select="if (contains($id, '.')) then substring-before($id, '.') else $id"/>
    <xsl:choose>
      <xsl:when test="starts-with($tk,'@xmlns')">
        <!--xsl:message>
          <xsl:value-of select="name($parentNode)"/>|<xsl:value-of select="$tk"/>|<xsl:value-of
          select="name($parentNode/namespace::*[local-name(.) = substring($tk,8)])"/>|<xsl:for-each
          select="$parentNode/namespace::*">
          <xsl:value-of select="local-name()"/>:<xsl:value-of select="."/>|</xsl:for-each>
          </xsl:message-->
        <xsl:variable name="node" select="$parentNode/namespace::*[local-name(.) = substring($tk,8)]"/>
        <xsl:variable name="nsNode">
          <t:namespace prefix="{local-name($node)}"><xsl:value-of select="$node"/></t:namespace>
        </xsl:variable>
        <xsl:apply-templates select="$nsNode" mode="applyNode"/>
      </xsl:when>
      <xsl:when test="starts-with($tk,'@')">
        <xsl:variable name="node" select="$parentNode/@*[name(.) = substring($tk,2)]"/>
        <xsl:apply-templates select="$node" mode="applyNode"/>
        <xsl:if test="not($node)">
          <xsl:call-template name="applyNode_fallback"/>
        </xsl:if>
      </xsl:when>
    	<xsl:when test="matches($tk,'^[0-9]+')">
    		<!--xsl:message>
    			<xsl:value-of select="name($parentNode)"/>[<xsl:value-of select="$tk"/>]: <xsl:value-of select="name($parentNode/node()[number($tk)])"/>
    			</xsl:message-->
    		<xsl:call-template name="applyNode">
    			<xsl:with-param name="parentNode" select="$parentNode/node()[number($tk)]"/>
    			<xsl:with-param name="id" select="substring-after($id,'.')"/>
    		</xsl:call-template>
    	</xsl:when>
    	<xsl:when test="$tk != ''">
    		<xsl:call-template name="applyNode">
    			<xsl:with-param name="parentNode" select="$parentNode//*[@id = $tk]"/>
    			<xsl:with-param name="id" select="substring-after($id,'.')"/>
    		</xsl:call-template>
    	</xsl:when>
    	<xsl:otherwise>
        <xsl:apply-templates select="$parentNode" mode="applyNode"/>
        <xsl:if test="not($parentNode)">
          <xsl:call-template name="applyNode_fallback"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template name="applyNode_fallback">
  </xsl:template>
  
  <xsl:template match="@*|node()" mode="applyNode">
    <xsl:apply-templates select="."/>
  </xsl:template>
  

  <!-- NodeID -->
  
  <xsl:function name="f:childIndex">
    <xsl:param name="node"/>
    <xsl:value-of select="count($node/preceding-sibling::node())+1"/>
  </xsl:function>
  
  <xsl:function name="f:nodeId">
    <xsl:param name="node"/>
    <xsl:apply-templates select="$node" mode="_fn_nodeId"/>
  </xsl:function>
  
  <xsl:template match="node()" mode="_fn_nodeId">
    <xsl:apply-templates select=".." mode="_fn_nodeId"/>
    <xsl:text>.</xsl:text>
    <xsl:value-of select="f:childIndex(.)"/>
  </xsl:template>
  
  <xsl:template match="/*" mode="_fn_nodeId">
    <xsl:text>1</xsl:text>
  </xsl:template>
  
  <xsl:template match="*[@id]" mode="_fn_nodeId">
    <xsl:value-of select="@id"/>
  </xsl:template>
  
  <xsl:function name="f:nodeById">
    <xsl:param name="nodeId"/>
    <xsl:param name="context"/>
    <xsl:apply-templates select="$context" mode="_fn_nodeById">
      <xsl:with-param name="nodeId" select="$nodeId"/>
    </xsl:apply-templates>
  </xsl:function>
  
  <xsl:template match="node()" mode="_fn_nodeById">
    <xsl:param name="nodeId"/>
    <xsl:variable name="id" select="substring-before($nodeId, '.')"/>
    <xsl:choose>
      <xsl:when test="normalize-space($id) = ''">
        <xsl:copy-of select="."/>
      </xsl:when>
      <xsl:when test="starts-with($id,'@xmlns')">
        <xsl:variable name="node" select="namespace::*[local-name(.) = substring($id,8)]"/>
        <t:namespace prefix="{local-name($node)}"><xsl:value-of select="$node"/></t:namespace>
      </xsl:when>
      <xsl:when test="starts-with($id,'@')">
        <xsl:copy-of select="@*[name(.) = substring($id,2)]"/>
      </xsl:when>
      <xsl:when test="matches($id,'^[0-9]+')">
        <xsl:apply-templates select="node()[number($id)]" mode="_fn_nodeById">
          <xsl:with-param name="nodeId" select="substring-after($nodeId, '.')"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select=".//*[@id = $id]" mode="_fn_nodeById">
          <xsl:with-param name="nodeId" select="substring-after($nodeId, '.')"/>
        </xsl:apply-templates>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:function name="f:xPath">
    <xsl:param name="context" as="node()"/>
    <xsl:param name="node"/>
    <xsl:text>.</xsl:text>
    <xsl:apply-templates select="$node" mode="_fn_xPath">
      <xsl:with-param name="context" select="$context"/>
    </xsl:apply-templates>
  </xsl:function>
  
  <xsl:template match="node()" mode="_fn_xPath">
    <xsl:param name="context" as="node()"/>
    <xsl:if test="not (. is $context)">
      <xsl:apply-templates select=".." mode="_fn_xPath">
        <xsl:with-param name="context" select="$context"/>
      </xsl:apply-templates>
      <xsl:text>/node()[</xsl:text>
      <xsl:value-of select="f:childIndex(.)"/>
      <xsl:text>]</xsl:text>
    </xsl:if>
  </xsl:template>
  
  <xsl:template match="@*" mode="_fn_xPath">
    <xsl:param name="context" as="node()"/>
    <xsl:if test="not (. is $context)">
      <xsl:apply-templates select=".." mode="_fn_xPath">
        <xsl:with-param name="context" select="$context"/>
      </xsl:apply-templates>
      <xsl:text>/@</xsl:text>
      <xsl:value-of select="node-name(.)"/>
    </xsl:if>
  </xsl:template>
  
</xsl:stylesheet>
